<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Go by Example 中文版: 通道的关闭</title>
    <link rel=stylesheet href="site.css">
  </head>
  <script>
      onkeydown = (e) => {
          
          if (e.key == "ArrowLeft") {
              window.location.href = 'non-blocking-channel-operations';
          }
          
          
          if (e.key == "ArrowRight") {
              window.location.href = 'range-over-channels';
          }
          
      }
  </script>
  <body>

    <div class="example" id="closing-channels">
      <h2><a href="./">Go by Example 中文版</a>: 通道的关闭</h2>
      
      <table>
        
        <tr>
          <td class="docs">
            <p><em>关闭</em> 一个通道意味着不能再向这个通道发送值了。
该特性可以向通道的接收方传达工作已经完成的信息。</p>

          </td>
          <td class="code empty leading">
            
          
          </td>
        </tr>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code leading">
            <a href="http://play.golang.org/p/dfMXpTUDw9H"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
          <div class="highlight"><pre><span class="kn">package</span> <span class="nx">main</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="kn">import</span> <span class="s">&quot;fmt&quot;</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>在这个例子中，我们将使用一个 <code>jobs</code> 通道，将工作内容，
从 <code>main()</code> 协程传递到一个工作协程中。
当我们没有更多的任务传递给工作协程时，我们将 <code>close</code> 这个 <code>jobs</code> 通道。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">jobs</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
    <span class="nx">done</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">bool</span><span class="p">)</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>这是工作协程。使用 <code>j, more := &lt;- jobs</code> 循环的从 <code>jobs</code> 接收数据。
根据接收的第二个值，如果 <code>jobs</code> 已经关闭了，
并且通道中所有的值都已经接收完毕，那么 <code>more</code> 的值将是 <code>false</code>。
当我们完成所有的任务时，会使用这个特性通过 <code>done</code> 通道通知 main 协程。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre>    <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">{</span>
            <span class="nx">j</span><span class="p">,</span> <span class="nx">more</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="nx">jobs</span>
            <span class="k">if</span> <span class="nx">more</span> <span class="p">{</span>
                <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;received job&quot;</span><span class="p">,</span> <span class="nx">j</span><span class="p">)</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;received all jobs&quot;</span><span class="p">)</span>
                <span class="nx">done</span> <span class="o">&lt;-</span> <span class="kc">true</span>
                <span class="k">return</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}()</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>使用 <code>jobs</code> 发送 3 个任务到工作协程中，然后关闭 <code>jobs</code>。</p>

          </td>
          <td class="code leading">
            
          <div class="highlight"><pre>    <span class="k">for</span> <span class="nx">j</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span> <span class="p">{</span>
        <span class="nx">jobs</span> <span class="o">&lt;-</span> <span class="nx">j</span>
        <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;sent job&quot;</span><span class="p">,</span> <span class="nx">j</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="nb">close</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
    <span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;sent all jobs&quot;</span><span class="p">)</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>使用前面学到的<a href="channel-synchronization">通道同步</a>方法等待任务结束。</p>

          </td>
          <td class="code">
            
          <div class="highlight"><pre>    <span class="o">&lt;-</span><span class="nx">done</span>
<span class="p">}</span>
</pre></div>

          </td>
        </tr>
        
      </table>
      
      <table>
        
        <tr>
          <td class="docs">
            
          </td>
          <td class="code leading">
            
          <div class="highlight"><pre><span class="gp">$</span> go run closing-channels.go
<span class="go">sent job 1</span>
<span class="go">received job 1</span>
<span class="go">sent job 2</span>
<span class="go">received job 2</span>
<span class="go">sent job 3</span>
<span class="go">received job 3</span>
<span class="go">sent all jobs</span>
<span class="go">received all jobs</span>
</pre></div>

          </td>
        </tr>
        
        <tr>
          <td class="docs">
            <p>根据 <code>关闭通道</code> 的思想，可以引出我们的下一个示例：遍历通道。</p>

          </td>
          <td class="code empty">
            
          
          </td>
        </tr>
        
      </table>
      
      
      <p class="next">
        下一个例子: <a href="range-over-channels">通道遍历</a>
      </p>
      
      <p class="footer">
        <a href="https://twitter.com/mmcgrana">@mmcgrana</a> 编写 | <a href="https://github.com/gobyexample-cn">gobyexample-cn</a> 翻译 | <a href="https://github.com/gobyexample-cn/gobyexample/issues">反馈</a> | <a href="https://github.com/gobyexample-cn/gobyexample">源码</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>      </p>
      </p>
    </div>
    <script>
      var codeLines = [];
      codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import \"fmt\"\u000A');codeLines.push('func main() {\u000A    jobs := make(chan int, 5)\u000A    done := make(chan bool)\u000A');codeLines.push('    go func() {\u000A        for {\u000A            j, more := \x3C-jobs\u000A            if more {\u000A                fmt.Println(\"received job\", j)\u000A            } else {\u000A                fmt.Println(\"received all jobs\")\u000A                done \x3C- true\u000A                return\u000A            }\u000A        }\u000A    }()\u000A');codeLines.push('    for j := 1; j \x3C= 3; j++ {\u000A        jobs \x3C- j\u000A        fmt.Println(\"sent job\", j)\u000A    }\u000A    close(jobs)\u000A    fmt.Println(\"sent all jobs\")\u000A');codeLines.push('    \x3C-done\u000A}\u000A');codeLines.push('');codeLines.push('');
    </script>
    <script src="site.js" async></script>
  </body>
</html>
